#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>
#include <errno.h>

#define PORT 8080
#define BUFFER_SIZE 1024
#define MAX_CLIENTS 50

typedef struct {
    int socket;
    struct sockaddr_in address;
    int uid;
    int active;
} client_t;

client_t *clients[MAX_CLIENTS];
pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
int uid_counter = 0;

/* 添加新客户端到列表 */
void add_client(client_t *cli);
/* 移除指定客户端 */
void remove_client(int uid);
/* 广播消息给所有客户端 */
void broadcast(char *msg, int sender_uid);
/* 私聊消息处理 */
void private_msg(int target_uid, char *msg, int sender_uid);
/* 客户端线程处理函数 */
void *client_handler(void *arg);

int main() {
    int server_fd;
    struct sockaddr_in addr;
    int opt = 1;

    /* 创建服务器套接字 */
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("套接字创建失败");
        exit(EXIT_FAILURE);
    }

    /* 设置套接字选项 */
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
        perror("套接字选项设置失败");
        exit(EXIT_FAILURE);
    }

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(PORT);

    /* 绑定端口 */
    if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("绑定失败");
        exit(EXIT_FAILURE);
    }

    /* 开始监听 */
    if (listen(server_fd, 10) < 0) {
        perror("监听失败");
        exit(EXIT_FAILURE);
    }

    printf("服务器运行中 (端口: %d)...\n", PORT);

    /* 主循环接收连接 */
    while (1) {
        struct sockaddr_in client_addr;
        socklen_t addr_len = sizeof(client_addr);
        int client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addr_len);

        if (client_fd < 0) {
            perror("接受连接失败");
            continue;
        }

        /* 创建客户端结构 */
        client_t *cli = (client_t *)malloc(sizeof(client_t));
        cli->socket = client_fd;
        cli->address = client_addr;

        /* 添加到客户端列表 */
        add_client(cli);

        /* 创建线程 */
        pthread_t tid;
        if (pthread_create(&tid, NULL, client_handler, (void *)cli) != 0) {
            perror("线程创建失败");
            close(client_fd);
            free(cli);
        }
    }

    close(server_fd);
    return 0;
}

/* 添加新客户端到列表 */
void add_client(client_t *cli) {
    pthread_mutex_lock(&clients_mutex);
    for (int i = 0; i < MAX_CLIENTS; ++i) {
        if (!clients[i]) {
            cli->uid = uid_counter++;
            cli->active = 1;
            clients[i] = cli;
            break;
        }
    }
    pthread_mutex_unlock(&clients_mutex);
}

/* 移除指定客户端 */
void remove_client(int uid) {
    pthread_mutex_lock(&clients_mutex);
    for (int i = 0; i < MAX_CLIENTS; ++i) {
        if (clients[i] && clients[i]->uid == uid) {
            clients[i]->active = 0;
            break;
        }
    }
    pthread_mutex_unlock(&clients_mutex);
}

/* 广播消息给所有客户端 */
void broadcast(char *msg, int sender_uid) {
    pthread_mutex_lock(&clients_mutex);
    char formatted[BUFFER_SIZE];
    snprintf(formatted, BUFFER_SIZE, "[%d] %s", sender_uid, msg);
    
    for (int i = 0; i < MAX_CLIENTS; ++i) {
        if (clients[i] && clients[i]->active && clients[i]->uid != sender_uid) {
            if (send(clients[i]->socket, formatted, strlen(formatted), MSG_NOSIGNAL) < 0) {
                perror("广播失败");
            }
        }
    }
    pthread_mutex_unlock(&clients_mutex);
}

/* 私聊消息处理 */
void private_msg(int target_uid, char *msg, int sender_uid) {
    pthread_mutex_lock(&clients_mutex);
    char formatted[BUFFER_SIZE];
    snprintf(formatted, BUFFER_SIZE, "(私聊来自%d) %s", sender_uid, msg);
    int found = 0;

    for (int i = 0; i < MAX_CLIENTS; ++i) {
        if (clients[i] && clients[i]->uid == target_uid && clients[i]->active) {
            if (send(clients[i]->socket, formatted, strlen(formatted), MSG_NOSIGNAL) < 0) {
                perror("私聊发送失败");
            }
            found = 1;
            break;
        }
    }

    /* 发送错误反馈 */
    if (!found) {
        char error_msg[BUFFER_SIZE];
        snprintf(error_msg, BUFFER_SIZE, "错误：用户 %d 不存在或已离线", target_uid);
        for (int i = 0; i < MAX_CLIENTS; ++i) {
            if (clients[i] && clients[i]->uid == sender_uid && clients[i]->active) {
                send(clients[i]->socket, error_msg, strlen(error_msg), MSG_NOSIGNAL);
                break;
            }
        }
    }
    pthread_mutex_unlock(&clients_mutex);
}

/* 客户端线程处理函数 */
void *client_handler(void *arg) {
    client_t *cli = (client_t *)arg;
    char buffer[BUFFER_SIZE];
    int leave_flag = 0;

    /* 发送欢迎消息 */
    char welcome[BUFFER_SIZE];
    snprintf(welcome, BUFFER_SIZE, "你的用户ID是：%d", cli->uid);
    send(cli->socket, welcome, strlen(welcome), MSG_NOSIGNAL);

    printf("客户端 %d 连接 (IP: %s)\n", cli->uid, inet_ntoa(cli->address.sin_addr));

    while (!leave_flag) {
        int recv_len = recv(cli->socket, buffer, BUFFER_SIZE, 0);
        if (recv_len > 0) {
            buffer[recv_len] = '\0';
            printf("收到 %d: %s\n", cli->uid, buffer);

            /* 命令解析 */
            if (strncmp(buffer, "/私聊 ", 4) == 0) {
                char *cmd = strtok(buffer, " ");
                char *target_str = strtok(NULL, " ");
                char *message = strtok(NULL, "\n");

                if (target_str && message) {
                    int target = atoi(target_str);
                    private_msg(target, message, cli->uid);
                } else {
                    char *err = "格式错误！正确格式：/私聊 目标UID 消息内容";
                    send(cli->socket, err, strlen(err), MSG_NOSIGNAL);
                }
            } else if (strcmp(buffer, "exit") == 0) {
                leave_flag = 1;
            } else {
                broadcast(buffer, cli->uid);
            }
        } else if (recv_len == 0) {
            printf("客户端 %d 正常断开\n", cli->uid);
            leave_flag = 1;
        } else {
            if (errno == ECONNRESET) {
                printf("客户端 %d 异常断开\n", cli->uid);
            } else {
                perror("接收错误");
            }
            leave_flag = 1;
        }
    }

    /* 安全关闭连接 */
    shutdown(cli->socket, SHUT_RDWR);
    close(cli->socket);
    
    /* 清理资源 */
    remove_client(cli->uid);
    free(cli);
    printf("客户端 %d 资源已释放\n", cli->uid);

    pthread_detach(pthread_self());
    return NULL;
}

